﻿using MyLibrary.Function;
using Prism.Commands;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using Serial_Communication.Common;
using Serial_Communication.Common.Models;
using Serial_Communication.Extensions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Threading;
using static Serial_Communication.Common.Models.SerialPortInfo;
using Parity = Serial_Communication.Common.Models.Parity;
using StopBits = Serial_Communication.Common.Models.StopBits;

namespace Serial_Communication.ViewModels
{
    public class SerialPortPageModel : BindableBase
    {
        private SerialPort ComDevice = new SerialPort();

        public DelegateCommand<string> ExecuteCommand { get; private set; }

        public SerialPortPageModel()
        {
            SerialPortInfo = new SerialPortInfo();

            ExecuteCommand = new DelegateCommand<string>(Execute);

            ComDevice.DataReceived += new SerialDataReceivedEventHandler(ReceivedText);

            DataInitialization();

        }

        private SerialPortInfo serialPortInfo;

        public SerialPortInfo SerialPortInfo
        {
            get { return serialPortInfo; }
            set { serialPortInfo = value; RaisePropertyChanged(); }
        }

        //委托命令执行事件
        private void Execute(string obj)
        {
            switch (obj)
            {
                case "OpenPort": OpenPort(); break;
                case "SendData": SendText(); break;
                case "CleanDisplay": CleanDisplay(); break;
                case "Circulate": CirculateSend(); break;
            }
        }

        public void OpenPort()
        {
            if (!SerialPort.GetPortNames().Any()||string.IsNullOrWhiteSpace(SerialPortInfo.SelectedSerialPortName))
            {
                MessageBox.Show("该设备没有发现端口(COM和LPT)", "警告");
                GetPortName();
                return;
            }
            switch (ComDevice.IsOpen)
            {
                case true:
                    try
                    {
                        ComDevice.Close();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "错误", MessageBoxButton.YesNo, MessageBoxImage.Information);
                        return;
                    }
                    SerialPortInfo.PortOpenButton= new string[4] { "打开串口", "#676767","TRUE" ,"FALSE"};
                    break;
                case false:
                    ComDevice.PortName = SerialPortInfo.SelectedSerialPortName;
                    ComDevice.BaudRate = SerialPortInfo.SelectedBaudRate;
                    ComDevice.DataBits = SerialPortInfo.SelectedDataBits;
                    ComDevice.StopBits = SerialPortInfo.SelectedStopBits;
                    ComDevice.Parity = serialPortInfo.SelectedParity;
                    try
                    {
                        ComDevice.Open();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "错误", MessageBoxButton.YesNo, MessageBoxImage.Information);
                        return;
                    }
                    SerialPortInfo.PortOpenButton = new string[4] { "关闭串口", "#7d4dcd", "FALSE", "TRUE" };
                    break;
            }
        }

        StringBuilder txtSendText = new StringBuilder("");
         string textboxSendText = "";
        private async Task SendText()
        {
            try
            {
                if (string.IsNullOrWhiteSpace(SerialPortInfo.SendText)) return;
                textboxSendText = SerialPortInfo.SendText.Trim().Replace(" ", "").ToUpper();
                int byteNum = 0;
                if (SerialPortInfo.SendSet.SendIsHex)
                {
                    byte[] arraySend = DataConvert.ToHexByteArray(textboxSendText);
                    ComDevice.Write(arraySend, 0, arraySend.Length);
                    byteNum = arraySend.Length;
                }
                else if (SerialPortInfo.SendSet.SendIsAscii)
                {
                    ComDevice.Write(textboxSendText);
                    byteNum = Encoding.ASCII.GetBytes(textboxSendText).Length;
                }

                if (SerialPortInfo.ReceiveSet.DisplaySend)
                {
                    if (SerialPortInfo.ReceiveSet.AutoLineFeed)
                    {
                        if (SerialPortInfo.SendSet.SendIsHex)
                        {
                            txtSendText.Insert(0, "\r\n");
                            txtSendText.Insert(0, DataConvert.ToHexByteString(textboxSendText));
                        }
                        else
                        {
                            txtSendText.Insert(0, "\r\n");
                            txtSendText.Insert(0, textboxSendText);
                        }
                    }
                    else
                    {
                        if (SerialPortInfo.SendSet.SendIsHex)
                        {
                            txtSendText.Insert(0, DataConvert.ToHexByteString(textboxSendText));
                        }
                        else
                        {
                            txtSendText.Insert(0, textboxSendText);
                        }
                    }
                    if (SerialPortInfo.ReceiveSet.DisplayTime)
                    {
                        txtSendText.Insert(0, "]  ");
                        txtSendText.Insert(0, DateTime.Now.ToString("HH : mm : ss - ffff"));
                        txtSendText.Insert(0, "[");
                    }
                    txtSendText.Insert(0, ">>  ");
                    SerialPortInfo.ReceiveText= txtSendText.ToString();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void ReceivedText(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] buffers = new byte[ComDevice.BytesToRead];
            ComDevice.Read(buffers, 0, buffers.Length);
            if (SerialPortInfo.ReceiveSet.AutoLineFeed)
            {
                if (SerialPortInfo.ReceiveSet.ReceiveIsHex)
                {
                    txtSendText.Insert(0, "\r\n");
                    txtSendText.Insert(0, DataConvert.ToHexByteString(BitConverter.ToString(buffers)));
                }
                else
                {
                    txtSendText.Insert(0, "\r\n");
                    txtSendText.Insert(0, Encoding.UTF8.GetString(buffers));
                }
            }
            else
            {
                if (SerialPortInfo.ReceiveSet.ReceiveIsHex)
                {
                    txtSendText.Insert(0, DataConvert.ToHexByteString(BitConverter.ToString(buffers)));
                }
                else
                {
                    txtSendText.Insert(0, Encoding.UTF8.GetString(buffers));
                }
            }
            if (SerialPortInfo.ReceiveSet.DisplayTime)
            {
                txtSendText.Insert(0, "]  ");
                txtSendText.Insert(0, DateTime.Now.ToString("HH : mm : ss - ffff"));
                txtSendText.Insert(0, "[");
            }
            txtSendText.Insert(0, "<<  ");
            SerialPortInfo.ReceiveText = txtSendText.ToString();
        }

        private void CirculateSend()
        {

            if (SerialPortInfo.SendSet.Circulate && ComDevice.IsOpen)
            {

                Task.Factory.StartNew(async () =>
                {
                    while (SerialPortInfo.SendSet.Circulate)
                    {
                        await SendText();
                        Thread.Sleep(SerialPortInfo.SendSet.CirculateTime);
                    }
                });
            }

        }

        public async Task SendCmdLoop()
        {
            while (SerialPortInfo.SendSet.Circulate)
            {
                await SendText();
                Thread.Sleep(SerialPortInfo.SendSet.CirculateTime);
            }
        }


        void DataInitialization()
        {
            GetPortName();

            SerialPortInfo.PortOpenButton = new string[4] { "打开串口", "#676767","TRUE" ,"FALSE"};

            SerialPortInfo.ReceiveSet = new ReceiveSet { ReceiveIsAscii = false, ReceiveIsHex = true, AutoLineFeed = true, DisplaySend = true, DisplayTime = true };

            SerialPortInfo.SendSet = new SendSet { SendIsAscii = false, SendIsHex = true, Circulate = false, CirculateTime=2000};

            SerialPortInfo.BaudRate = new List<BaudRate>
            {
                new BaudRate{Description="300",SelectedModel=300},
                new BaudRate{Description="600",SelectedModel=600},
                new BaudRate{Description="1200",SelectedModel=1200},
                new BaudRate{Description="2400",SelectedModel=2400},
                new BaudRate{Description="4800",SelectedModel=4800},
                new BaudRate{Description="9600",SelectedModel=9600},
                new BaudRate{Description="14400",SelectedModel=14400},
                new BaudRate{Description="19200",SelectedModel=19200},
                new BaudRate{Description="38400",SelectedModel=38400},
                new BaudRate{Description="56000",SelectedModel=56000},
                new BaudRate{Description="57600",SelectedModel=57600},
                new BaudRate{Description="115200",SelectedModel=115200},
                new BaudRate{Description="128000",SelectedModel=128000},
                new BaudRate{Description="256000",SelectedModel=256000},
                new BaudRate{Description="460800",SelectedModel=460800},
                new BaudRate{Description="512000",SelectedModel=512000},
                new BaudRate{Description="750000",SelectedModel=750000},
                new BaudRate{Description="921600",SelectedModel=921600},
                new BaudRate{Description="1500000",SelectedModel=1500000},
            };
            SerialPortInfo.SelectedBaudRate = SerialPortInfo.BaudRate[5].SelectedModel;

            SerialPortInfo.DataBits = new List<DataBits>
            {
                new DataBits{Description="5",SelectedModel=5},
                new DataBits{Description="6",SelectedModel=6},
                new DataBits{Description="7",SelectedModel=7},
                new DataBits{Description="8",SelectedModel=8},
            };
            SerialPortInfo.SelectedDataBits = SerialPortInfo.DataBits[3].SelectedModel;

            SerialPortInfo.StopBits = new List<StopBits>
            {
                new StopBits { Description = "One", SelectedModel = System.IO.Ports.StopBits.One },
                new StopBits { Description = "OnePointFive", SelectedModel = System.IO.Ports.StopBits.OnePointFive },
                new StopBits { Description = "Two", SelectedModel = System.IO.Ports.StopBits.Two },

            };
            SerialPortInfo.SelectedStopBits = SerialPortInfo.StopBits[0].SelectedModel;

            SerialPortInfo.Parity = new List<Parity>
            {
                new Parity { Description = "None", SelectedModel = System.IO.Ports.Parity.None },
                new Parity { Description = "Odd", SelectedModel = System.IO.Ports.Parity.Odd },
                new Parity { Description = "Even", SelectedModel = System.IO.Ports.Parity.Even },
                new Parity { Description = "Mark", SelectedModel = System.IO.Ports.Parity.Mark },

            };
            SerialPortInfo.SelectedParity = SerialPortInfo.Parity[0].SelectedModel;
        }

        void GetPortName()
        {
            SerialPortInfo.SerialPortName = new List<string>();
            string[] SerialPortName = SerialPort.GetPortNames();
            SerialPortInfo.SerialPortName = SerialPortName.ToList();
            if(SerialPort.GetPortNames().Any())
            {
                SerialPortInfo.SelectedSerialPortName = serialPortInfo.SerialPortName[0];
            }
        }

        public void CleanDisplay()
        {
            SerialPortInfo.ReceiveText = "";
            txtSendText = new StringBuilder("");
        }
    }
}
